#pragma once 
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstdlib>
#include <unistd.h>
#include <pthread.h>
#include "Log.hpp"

#define BACKLOG 5

class Tcpserver{
private:
  int port;
  int listen_sock;
  static Tcpserver* svr;
  Tcpserver()
  {}
  Tcpserver(const Tcpserver&)=delete;
  Tcpserver* operator=(const Tcpserver&)=delete;
public:
  int Getsocket()
  {
    return listen_sock;
  }
  static Tcpserver* Getinstance(int port)
  {
    static pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
    if(svr==nullptr)
    {
      pthread_mutex_lock(&lock);
      if(svr==nullptr)
      {
        svr=new Tcpserver();
        svr->port=port;
        svr->Initserver();
      }
      pthread_mutex_unlock(&lock);
    }
    return svr;
  }

  void Initserver()
  {
    Socket();
    Bind();
    Listen();
    LOG(INFO,"Init seccess");
  }

  void Socket()
  {
    listen_sock=socket(AF_INET,SOCK_STREAM,0);
    if(listen_sock<0)
    {
      LOG(FATAL,"socket err");
      exit(1);
    }
    LOG(INFO,"socket success");
    int opt=1;
    //主动退出服务的时候再次重启防止被占用
    setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
  }

  void Bind()
  {
    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_port=htons(port);
    local.sin_addr.s_addr=INADDR_ANY;

    if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0){
      LOG(FATAL,"Bind err");
      exit(2);
    }
    LOG(INFO,"Bind  success");
  }

  void Listen()
  {
    if(listen(listen_sock,BACKLOG)<0){
      LOG(FATAL,"listen err");
      exit(3);
    }
    LOG(INFO,"listen   success");
  }

  ~Tcpserver()
  {
    if(listen_sock)
      close(listen_sock);
  }
};
Tcpserver* Tcpserver::svr=nullptr;
